home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / MAIL / RMAIL.C < prev    next >
C/C++ Source or Header  |  1993-04-15  |  41KB  |  1,007 lines

  1. /*--------------------------------------------------------------------*/
  2. /*       r m a i l . c                                                */
  3. /*                                                                    */
  4. /*       Delivery agent for UUPC/extended                             */
  5. /*--------------------------------------------------------------------*/
  6.  
  7. /*--------------------------------------------------------------------*/
  8. /*    Changes Copyright (c) 1989 by Andrew H. Derbyshire.             */
  9. /*                                                                    */
  10. /*    Changes Copyright (c) 1990-1993 by Kendra Electronic            */
  11. /*    Wonderworks.                                                    */
  12. /*                                                                    */
  13. /*    All rights reserved except those explicitly granted by the      */
  14. /*    UUPC/extended license agreement.                                */
  15. /*--------------------------------------------------------------------*/
  16.  
  17. /*--------------------------------------------------------------------*/
  18. /*                          RCS Information                           */
  19. /*--------------------------------------------------------------------*/
  20.  
  21. /*
  22.  *    $Id: RMAIL.C 1.8 1993/04/15 03:17:21 ahd Exp $
  23.  *
  24.  *    $Log: RMAIL.C $
  25.  * Revision 1.8  1993/04/15  03:17:21  ahd
  26.  * Correct conditions under which name in userp structure used
  27.  *
  28.  * Revision 1.7  1993/04/13  02:26:30  ahd
  29.  * Make return codes more unique
  30.  *
  31.  * Revision 1.6  1993/04/11  00:33:05  ahd
  32.  * Global edits for year, TEXT, etc.
  33.  *
  34.  * Revision 1.5  1992/12/05  23:38:43  ahd
  35.  * Let logger close the log, not rmail
  36.  *
  37.  * Revision 1.4  1992/12/04  01:00:27  ahd
  38.  * Add copyright messages
  39.  *
  40.  */
  41.  
  42. /*--------------------------------------------------------------------*/
  43. /*    Function:   Stand alone mail delivery module for                */
  44. /*                UUPC/extended                                       */
  45. /*    Language:   Borland C++ 3.1 (ANSI C mode) or Microsoft C 6.0.   */
  46. /*    Arguments:  One or more addresses to deliver mail to            */
  47. /*                or "-t" to direct rmail to read the addresses       */
  48. /*                from the RFC-822 header.                            */
  49. /*                A third mode of operation is to specify '-w' and/   */
  50. /*                or '-s subject' followed by one or more addresses   */
  51. /*                with optional carbon copy flags (-c or -b) before   */
  52. /*                additional addresses.  This causes rmail to         */
  53. /*                function like a bare bones batch version of the     */
  54. /*                MAIL program; a valid RFC-822 header is generated   */
  55. /*                and the mail is delivered, aliases are not expanded */
  56. /*                and the mail is not locally logged.  (The current   */
  57. /*                user id as the from address is used unless the      */
  58. /*                environment variable LOGNAME is set, in which case  */
  59. /*                it is used.)                                        */
  60. /*                Optional argument "-f" to denote file to read in    */
  61. /*                place of stdin.                                     */
  62. /*                Optional argument "-F" to denote file to read in    */
  63. /*                place of stdin and DELETE after readering.          */
  64. /*                Optional argument "-x" to for debug level           */
  65. /*    Input:      mail to be delivered, with RFC-822 header, on       */
  66. /*                stdin.                                              */
  67. /*    Output:     'From' and 'Received:' headers are added,           */
  68. /*                'Bcc:' headers are removed, and the mail is         */
  69. /*                delivered to one or more local users and/or         */
  70. /*                one or more remote users.                           */
  71. /*    Exit code:  0  Success                                          */
  72. /*                1  One or more letters not delivered                */
  73. /*                2  No mail delivered                                */
  74. /*                3 Configuration file error                          */
  75. /*                4 Invalid option/help specified                     */
  76. /*                5 Input/output error                                */
  77. /*                6 Input/output error                                */
  78. /*                7 Input/output error                                */
  79. /*                                                                    */
  80. /*    Note:       When parsing RFC-822 headers, this program          */
  81. /*                expects them to be "well-behaved", that is in       */
  82. /*                format generated by UUPC/extended.  This implies:   */
  83. /*                                                                    */
  84. /*                      One address per line                          */
  85. /*                                                                    */
  86. /*                      Resent- headers, if any, before the original  */
  87. /*                      headers.                                      */
  88. /*                                                                    */
  89. /*                      From: header must precede To: header.         */
  90. /*                                                                    */
  91. /*                      To: header must precede Cc: and Bcc: headers. */
  92. /*                                                                    */
  93. /*                      Cc: and Bcc: headers must be together (one    */
  94. /*                      after the other)                              */
  95. /*                                                                    */
  96. /*                      The MUA has prefixed any obsolete Resent-     */
  97. /*                      headers by X-                                 */
  98. /*                                                                    */
  99. /*    Note:       The "-t" flag is supported by BSD sendmail for the  */
  100. /*                purpose listed above, but we also turn use it to    */
  101. /*                control other special options, all of which         */
  102. /*                basically cause the program to act more like a      */
  103. /*                local mailer than a remote mailer; these options    */
  104. /*                include:                                            */
  105. /*                                                                    */
  106. /*                      Stripping off blind carbon copies             */
  107. /*                                                                    */
  108. /*                      Generating the UUCP From line differently     */
  109. /*--------------------------------------------------------------------*/
  110.  
  111. /*--------------------------------------------------------------------*/
  112. /*                        System include files                        */
  113. /*--------------------------------------------------------------------*/
  114.  
  115. #include <stdio.h>
  116. #include <ctype.h>
  117. #include <io.h>
  118. #include <stdlib.h>
  119. #include <string.h>
  120. #include <time.h>
  121. #include <signal.h>
  122.  
  123. /*--------------------------------------------------------------------*/
  124. /*                     Application include files                      */
  125. /*--------------------------------------------------------------------*/
  126.  
  127. #include "lib.h"
  128. #include "address.h"
  129. #include "arpadate.h"
  130. #include "deliver.h"
  131. #include "getopt.h"
  132. #include "hlib.h"
  133. #include "hostable.h"
  134. #include "logger.h"
  135. #include "security.h"
  136. #include "usertabl.h"
  137. #include "timestmp.h"
  138. #include "catcher.h"
  139.  
  140. /*--------------------------------------------------------------------*/
  141. /*                           Local defines                            */
  142. /*--------------------------------------------------------------------*/
  143.  
  144. #define  MOPLEN      10          /* Length of formatted header lines */
  145. #define  UUCPFROM    "From "     /* Length of UUCP incoming mail     */
  146.  
  147. /*--------------------------------------------------------------------*/
  148. /*                   Prototypes for internal files                    */
  149. /*--------------------------------------------------------------------*/
  150.  
  151. static boolean CopyTemp( void );
  152.  
  153. static void ParseFrom( void );
  154.  
  155. static char **Parse822( boolean *header,
  156.                         size_t *count);
  157.  
  158. static void Terminate( const int rc);
  159.  
  160.  static void PutHead( const char *label,
  161.                       const char *operand,
  162.                       FILE *stream,
  163.                       const boolean resent);
  164.  
  165. static boolean DaemonMail( const char *subject,
  166.                            char **address,
  167.                            int count );
  168.  
  169.  
  170.  static void usage( void );
  171.  
  172. /*--------------------------------------------------------------------*/
  173. /*                          Global variables                          */
  174. /*--------------------------------------------------------------------*/
  175.  
  176.  currentfile();               /* Declare file name for checkref()    */
  177.  char *tempname = NULL;       /* Pointer to temporary input file     */
  178.  char *namein = CONSOLE;
  179.  FILE *datain = stdin;        /* Handle for reading input mail       */
  180.  FILE *dataout = NULL;        /* Handle for the output of mail       */
  181.  char fromuser[MAXADDR] = ""; /* User id of originator               */
  182.  char fromnode[MAXADDR] = ""; /* Node id of originator               */
  183.  char *now;                   /* Time stamp for Received: banner     */
  184.  
  185.  static char received[] = "Received:";
  186.  static char receivedlen = sizeof( received) - 1;
  187.  
  188. /*--------------------------------------------------------------------*/
  189. /*                            main program                            */
  190. /*--------------------------------------------------------------------*/
  191.  
  192. void main(int argc, char **argv)
  193. {
  194.    boolean ReadHeader = FALSE;   /* TRUE = Parse RFC-822 headers      */
  195.  
  196.    int  option;                  /* For parsing option list           */
  197.    char **address;               /* Pointer to list of target
  198.                                     addresses                         */
  199.    char *token;
  200.    size_t addressees;            /* Number of targets in address      */
  201.    size_t count;                 /* Loop variable for delivery        */
  202.    size_t delivered = 0;         /* Count of successfull deliveries   */
  203.    boolean header = TRUE;
  204.    boolean DeleteInput = FALSE;
  205.  
  206.    boolean daemon = FALSE;
  207.  
  208.    char *subject = NULL;
  209.  
  210. /*--------------------------------------------------------------------*/
  211. /*    Make a copy of the Borland copyright for debugging purposes     */
  212. /*--------------------------------------------------------------------*/
  213.  
  214. #if defined(__CORE__)
  215.    copywrong = strdup(copyright);
  216.    checkref(copywrong);
  217. #endif
  218.  
  219.    banner( argv);
  220.  
  221.    now = arpadate();          /* Set the current date                */
  222.    debuglevel = -1;           /* Set default so we can detect it     */
  223.  
  224. /*--------------------------------------------------------------------*/
  225. /* Load the UUPC/extended configuration file, and exit if any errors  */
  226. /*--------------------------------------------------------------------*/
  227.  
  228.    if (!configure(B_MTA))
  229.       Terminate(3);
  230.  
  231. /*--------------------------------------------------------------------*/
  232. /*                    Handle control-C interrupts                     */
  233. /*--------------------------------------------------------------------*/
  234.  
  235.     if( signal( SIGINT, ctrlchandler ) == SIG_ERR )
  236.     {
  237.         printmsg( 0, "Couldn't set SIGINT\n" );
  238.         panic();
  239.     }
  240.  
  241. /*--------------------------------------------------------------------*/
  242. /*                       Begin logging messages                       */
  243. /*--------------------------------------------------------------------*/
  244.  
  245.    openlog( NULL );
  246.  
  247. /*--------------------------------------------------------------------*/
  248. /*                      Parse our operand flags                       */
  249. /*--------------------------------------------------------------------*/
  250.  
  251.    while ((option = getopt(argc, argv, "ws:tF:f:x:")) != EOF)
  252.    {
  253.       switch (option) {
  254.       case 'w':
  255.          daemon = TRUE;
  256.          break;
  257.  
  258.       case 's':
  259.          subject = optarg;
  260.          daemon = TRUE;
  261.          break;
  262.  
  263.       case 't':
  264.          ReadHeader = TRUE;
  265.          break;
  266.  
  267.       case 'x':
  268.          debuglevel = atoi(optarg);
  269.          break;
  270.  
  271.       case 'F':
  272.          DeleteInput = TRUE;
  273.       case 'f':
  274.          namein = optarg;
  275.          datain = FOPEN(namein , "r",TEXT_MODE);
  276.          break;
  277.  
  278.       case '?':
  279.          usage();
  280.          Terminate(4);
  281.       } /* switch */
  282.    } /* while */
  283.  
  284.    if ( debuglevel > 1 )
  285.    {
  286.       for ( count = 1; (int) count < argc; count ++)
  287.          printmsg(4,"rmail argv[%d] = \"%s\"", count, argv[count] );
  288.    } /* if ( debuglevel > 4 ) */
  289.  
  290.    if ((optind == argc) != ReadHeader)
  291.    {
  292.       puts("Missing/extra parameter(s) at end.");
  293.       Terminate(4);
  294.    }
  295.  
  296.    remoteMail = ! (ReadHeader || daemon);
  297.                               /* If not reading headers, must be in
  298.                                  normal rmail mode ...               */
  299.  
  300. /*--------------------------------------------------------------------*/
  301. /*    If in local mode and the user doesn't want output, suppress     */
  302. /*    routine delivery messages                                       */
  303. /*--------------------------------------------------------------------*/
  304.  
  305.    if ( debuglevel == -1 )
  306.    {
  307.       if (remoteMail)
  308.          debuglevel = 1;
  309.       else
  310.          debuglevel = (int) bflag[F_VERBOSE];
  311.    }
  312.  
  313. /*--------------------------------------------------------------------*/
  314. /*               Verify we have input stream available                */
  315. /*--------------------------------------------------------------------*/
  316.  
  317.    if (datain == NULL )
  318.    {
  319.       printerr(namein);
  320.       Terminate(6);
  321.    } /* if */
  322.  
  323. /*--------------------------------------------------------------------*/
  324. /*                   Open up the output data stream                   */
  325. /*--------------------------------------------------------------------*/
  326.  
  327.    tempname = mktempname( NULL , "TMP");
  328.    dataout = FOPEN(tempname, "w",TEXT_MODE);
  329.  
  330.    if (dataout == NULL)
  331.    {
  332.       printmsg(0,"Cannot open temporary file \"%s\" for output",
  333.             tempname);
  334.       Terminate(5);
  335.    } /* if */
  336.  
  337. /*--------------------------------------------------------------------*/
  338. /*   If in local mail mode, make up a list of addresses to mail to    */
  339. /*--------------------------------------------------------------------*/
  340.  
  341.    if ( daemon )
  342.    {
  343.       addressees = argc - optind;
  344.       address = &argv[optind];
  345.       DaemonMail( subject, address, addressees );
  346.       header = FALSE;
  347.    }
  348.    else if (ReadHeader)
  349.       address = Parse822( &header, &addressees );
  350.    else {
  351.       ParseFrom();               /* Copy remote header instead       */
  352.       addressees = argc - optind;
  353.       address = &argv[optind];
  354.    } /* if */
  355.  
  356.    if ( addressees == 0 )        /* Can we deliver mail?             */
  357.    {
  358.       printmsg(0, "No addressees to deliver to!");
  359.       Terminate( 2 );            /* No --> Execute punt formation    */
  360.    }
  361.  
  362. /*--------------------------------------------------------------------*/
  363. /*       Copy the rest of the input file into our holding tank        */
  364. /*--------------------------------------------------------------------*/
  365.  
  366.    header = CopyTemp( ) && header ;
  367.    if (header)                   /* Was the header ever terminated?  */
  368.    {
  369.       printmsg(0,"rmail: Improper header, adding trailing newline");
  370.       fputc('\n', dataout);      /* If not, it is now ...            */
  371.    }
  372.  
  373.    fclose(datain);
  374.    fclose(dataout);
  375.  
  376.    if (DeleteInput)              /* Make room for more data on disk  */
  377.       remove(namein);
  378.  
  379. /*--------------------------------------------------------------------*/
  380. /*        Determine requestor node and user id for remote mail        */
  381. /*--------------------------------------------------------------------*/
  382.  
  383.  
  384. /*--------------------------------------------------------------------*/
  385. /*                    Perform delivery of the mail                    */
  386. /*--------------------------------------------------------------------*/
  387.  
  388.    while ((token = strpbrk(tempname ,"/")) != NULL)
  389.       *token = '\\';
  390.  
  391.    for ( count = 0; count < addressees; count++)
  392.          if ( *address[count] == '-')
  393.             delivered ++;     /* Ignore option flags on delivery     */
  394.          else
  395.             delivered += Deliver(tempname, address[count], FALSE, TRUE);
  396.  
  397. /*--------------------------------------------------------------------*/
  398. /*                       Terminate the program                        */
  399. /*--------------------------------------------------------------------*/
  400.  
  401.    printmsg(8,"rmail: %d addressees, delivered to %d mailboxes",
  402.             addressees, delivered);
  403.  
  404.    if ( delivered >= addressees )
  405.       Terminate( 0 );         /* All mail delivered                  */
  406.    else if ( delivered == 0 )
  407.       Terminate( 2 );         /* No mail delivered                   */
  408.    else
  409.       Terminate (1 );         /* Some mail delivered                 */
  410.  
  411. } /* main */
  412.  
  413. /*--------------------------------------------------------------------*/
  414. /*    T e r m i n a t e                                               */
  415. /*                                                                    */
  416. /*    Cleanup open files and return to operating system               */
  417. /*--------------------------------------------------------------------*/
  418.  
  419. static void Terminate( const int rc)
  420. {
  421.    if (tempname != NULL)         /* Did temporary file get named?    */
  422.    {
  423.       if (datain != stdin)       /* Non-standard input?              */
  424.         fclose(stdin);           /* Yes --> Close it                 */
  425.       remove(tempname);          /* Purge temporary file, if exists  */
  426.    } /* if */
  427.  
  428.    exit( rc );                   /* Return to operating systems      */
  429. }  /* Terminate */
  430.  
  431. /*--------------------------------------------------------------------*/
  432. /*    P a r s e F r o m                                               */
  433. /*                                                                    */
  434. /*    Read the from address of incoming data from UUCP                */
  435. /*--------------------------------------------------------------------*/
  436.  
  437. static void ParseFrom()
  438. {
  439.    static char from[] = "From ";
  440.    static char remote[] = "remote from ";
  441.    static int  remotelen = sizeof remote - 1;
  442.    static int  fromlen = sizeof from - 1;
  443.    char *token;
  444.    char buf[BUFSIZ];
  445.    boolean hit;
  446.  
  447. /*--------------------------------------------------------------------*/
  448. /*                Use UUXQT Information, if available                 */
  449. /*--------------------------------------------------------------------*/
  450.  
  451.    token = getenv( UU_MACHINE );
  452.    if ( token == NULL )
  453.       *fromnode = '\0';
  454.    else {
  455.       strncpy( fromnode, token , sizeof fromnode );
  456.       fromnode[ sizeof fromnode - 1 ] = '\0';
  457.    }
  458.  
  459.    fgets(buf, BUFSIZ , datain);
  460.    hit = equaln(buf, from, fromlen );
  461.  
  462.    if (hit)
  463.    {
  464.       int nodelen = strlen( fromnode ) + 1; /* Plus ! */
  465.       char *s;
  466.       token = strtok( &buf[ fromlen ], " ");
  467.       s = strtok( NULL, "\n");
  468.  
  469.       if (strlen( token ) + nodelen >= MAXADDR)
  470.       {
  471.          char *next;
  472.          token = strtok( token, "!" );
  473.  
  474.          while ((next = strtok( NULL , "!")) != NULL )
  475.          {
  476.             token = next;
  477.             if (strlen( next ) + nodelen < MAXADDR)
  478.                break;
  479.          } /* while */
  480.       } /* if */
  481.  
  482.       strncpy(fromuser, token , sizeof fromuser );
  483.       fromuser[ sizeof fromuser - nodelen ] = '\0';
  484.  
  485.       if ( *fromnode == '\0')
  486.       {
  487.          while ( *s != '\0')
  488.          {
  489.             if equaln(s, remote, remotelen)
  490.                break;
  491.             else
  492.                s++;
  493.          } /* while */
  494.          strncpy( fromnode ,
  495.                 (*s == '\0') ? E_nodename : s + remotelen ,
  496.                  sizeof fromnode );
  497.          fromnode[ sizeof fromnode -1 ] = '\0';
  498.       } /* if ( *fromnode != '\0') */
  499.  
  500.    } /* if */
  501.    else {
  502.       if ( *fromnode == '\0')
  503.          strcpy(fromnode, E_nodename );
  504.       strcpy(fromuser, "/dev/null");
  505.    } /* else */
  506.  
  507. /*--------------------------------------------------------------------*/
  508. /*       Generate required "From " and "Received" header lines        */
  509. /*--------------------------------------------------------------------*/
  510.  
  511.    fprintf(dataout,"%-10s from %s by %s (%s %s) with UUCP;\n%-10s %s\n",
  512.             "Received:", fromnode, E_domain, compilep, compilev,
  513.             " ", now);
  514.  
  515. /*--------------------------------------------------------------------*/
  516. /*    If what we read wasn't a From line, write into the new file     */
  517. /*--------------------------------------------------------------------*/
  518.  
  519.    if (!hit)
  520.    {
  521.       fputs(buf, dataout);
  522.       if (ferror(dataout))
  523.       {
  524.          printerr(tempname);
  525.          Terminate(6);
  526.       } /* if */
  527.    } /* if */
  528.  
  529. /*--------------------------------------------------------------------*/
  530. /*              Determine the requestor user id and node              */
  531. /*--------------------------------------------------------------------*/
  532.  
  533.    token = getenv( UU_USER ); /* Get exactly what remote told us     */
  534.  
  535.    if ( token != NULL )
  536.    {                     /* Use exactly what remote told us     */
  537.       ruser = strtok( token , WHITESPACE );
  538.       rnode = strtok( NULL  , WHITESPACE );
  539.    } /* else */
  540.  
  541.    if ((rnode == NULL) || (strchr(rnode,'.') == NULL ))
  542.                               /* Did it tell us the domain?          */
  543.    {                          /* No --> Use from information         */
  544.       char node[MAXADDR];
  545.       char user[MAXADDR];
  546.  
  547.       sprintf(buf ,"%s!%s", fromnode, fromuser);
  548.       user_at_node(buf , buf, node, user);
  549.       ruser = newstr( user );
  550.       rnode = newstr( node );
  551.    }
  552.  
  553.    uuser = "uucp";            /* Effective id is always our daemon   */
  554.  
  555. }  /* ParseFrom */
  556.  
  557. /*--------------------------------------------------------------------*/
  558. /*    P a r s e 8 2 2                                                 */
  559. /*                                                                    */
  560. /*    Parse an RFC-822 header generated by that esteemed mail user    */
  561. /*    agent, UUPC/extended's MAIL.                                    */
  562. /*                                                                    */
  563. /*    Note that we parse the header in the format we KNOW that UUPC   */
  564. /*    generated it in:  "To:", "Cc:", "Bcc:", optionally prefixed     */
  565. /*    by "Resent-".  We also know that mail comes in one address      */
  566. /*    per line, and that the Resent- headers, if any, precede the     */
  567. /*    original headers.                                               */
  568. /*--------------------------------------------------------------------*/
  569.  
  570. static char **Parse822( boolean *header,
  571.                         size_t *count)
  572. {
  573.  
  574. /*--------------------------------------------------------------------*/
  575. /*  Define the headers we will be examining and variables for their   */
  576. /*                              lengths                               */
  577. /*--------------------------------------------------------------------*/
  578.  
  579.    static char *to     = "Resent-To:";
  580.    static char *cc     = "Resent-Cc:";
  581.    static char *bcc    = "Resent-Bcc:";
  582.    static char *resent = "Resent-";
  583.    static char *from   = "Resent-From:";
  584.  
  585.    size_t tolen;
  586.    size_t cclen;
  587.    size_t bcclen;
  588.    size_t resentlen =  strlen(resent);
  589.    size_t offset = resentlen; /* Subscript for examining headers,
  590.                                  which allows us to ignore Resent-   */
  591.    size_t fromlen =  strlen( &from[offset] );
  592.    size_t allocated = 5;      /* Reasonable first size for address   */
  593.                               /* Note: MUST BE AT LEAST 2 because we
  594.                                        add 50% below!                */
  595.    boolean blind = FALSE;
  596.  
  597.    char **addrlist = calloc( sizeof *addrlist , allocated);
  598.    char buf[BUFSIZ];          /* Input buffer for reading header     */
  599.    char address[MAXADDR];     /* Buffer for parsed address           */
  600.    char path[MAXADDR];
  601.    char *token;               /* For parsing line in buf             */
  602.    struct HostTable *hostp;
  603.  
  604. /*--------------------------------------------------------------------*/
  605. /*                          Begin processing                          */
  606. /*--------------------------------------------------------------------*/
  607.  
  608.    *count = 0;                /* No addresses discovered yet         */
  609.    checkref(addrlist);        /* Verify we had room for the list     */
  610.  
  611.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  612.               "Received:",E_domain,compilep, compilev,
  613.               " ", now );
  614.  
  615. /*--------------------------------------------------------------------*/
  616. /*                        Find the From: line                         */
  617. /*--------------------------------------------------------------------*/
  618.  
  619.    do {
  620.       if (fgets( buf, BUFSIZ, datain) == NULL)  /* End of file?      */
  621.          return NULL;         /* Yes --> Very bad, report error      */
  622.       fputs(buf, dataout );
  623.       if (*buf == '\n')       /* End of the header?                  */
  624.          return NULL;         /* Yes --> Very bad, report error      */
  625.       else if (equalni(resent, buf, resentlen))
  626.       {
  627.          offset = 0;
  628.          fromlen = strlen(&from[offset]);
  629.       } /* if */
  630.       else if (equalni(received, buf, receivedlen))
  631.          hops++;
  632.    } while (!equalni(&from[offset], buf, fromlen));
  633.  
  634.    strtok( buf , WHITESPACE);    /* Drop the leading token           */
  635.    token = strtok( NULL, "\n");  /* Get the token with From: addr    */
  636.    ExtractAddress( address, token, FALSE );
  637.                                  /* Get the From: address itself     */
  638.    user_at_node(address, path, fromnode, fromuser);
  639.                                  /* Separate portions of the address */
  640.  
  641. /*--------------------------------------------------------------------*/
  642. /*               Generate a Sender: line if we need it                */
  643. /*--------------------------------------------------------------------*/
  644.  
  645.    if (equal(fromnode,HostAlias(E_fdomain))) /* Same as hidden site? */
  646.       strcpy(fromnode, E_nodename);/* Yes --> Declare as local system  */
  647.  
  648.    hostp = checkname( fromnode );   /* Look up real system name      */
  649.  
  650.    if (!equal(fromuser,E_mailbox) ||
  651.        (hostp == BADHOST) || (hostp->hstatus != localhost))
  652.    {
  653.       sprintf(buf, "%s <%s@%s>", E_name, E_mailbox, E_fdomain );
  654.       PutHead("Sender:", buf, dataout , offset == 0 );
  655.    } /* if */
  656.  
  657. /*--------------------------------------------------------------------*/
  658. /*      Set UUCP requestor name while we've got the information       */
  659. /*--------------------------------------------------------------------*/
  660.  
  661.    if ((hostp != BADHOST) && (hostp->hstatus == localhost))
  662.       rnode = bflag[F_BANG] ? E_nodename : E_fdomain;
  663.                               /* Use full domain address, if possible */
  664.    else
  665.       rnode = fromnode;
  666.  
  667.    uuser = ruser = fromuser;  /* User and requestor always the same
  668.                                  for locally generated mail          */
  669.  
  670. /*--------------------------------------------------------------------*/
  671. /*                       Generate a message-id                        */
  672. /*--------------------------------------------------------------------*/
  673.  
  674.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , E_nodename, E_domain);
  675.    PutHead("Message-ID:", buf, dataout , offset == 0 );
  676.    PutHead(NULL, NULL, dataout , FALSE );
  677.  
  678. /*--------------------------------------------------------------------*/
  679. /*                 Locate the To: or Resent-To: line                  */
  680. /*--------------------------------------------------------------------*/
  681.  
  682.    tolen =    strlen( &to[offset] );
  683.  
  684.    do {
  685.       if (fgets( buf, BUFSIZ, datain ) == NULL)  /* End of file?     */
  686.          return NULL;         /* Yes --> Very bad, report error      */
  687.       fputs(buf, dataout );
  688.       if (*buf == '\n')       /* End of the header?                  */
  689.          return NULL;         /* Yes --> Very bad, report error      */
  690.       else if (equalni(received, buf, receivedlen))
  691.          hops++;
  692.    } while ( !equalni(&to[offset] , buf , tolen ));
  693.  
  694.    token = strpbrk( buf ," \t");
  695.  
  696. /*--------------------------------------------------------------------*/
  697. /*                Proccess the rest of the addressees                 */
  698. /*--------------------------------------------------------------------*/
  699.  
  700.    cclen =    strlen( &cc[offset] );
  701.    bcclen =   strlen( &bcc[offset] );
  702.  
  703.    do {
  704.       if (allocated == (*count+1))  /* Do we have room for addr?     */
  705.       {
  706.          allocated += allocated / 2;   /* Choose larger array size   */
  707.          addrlist = realloc( addrlist ,
  708.                              allocated * sizeof( *addrlist ));
  709.          checkref(addrlist);  /* Verify the allocation worked        */
  710.       } /* if */
  711.  
  712.       ExtractAddress( address, token, FALSE );  /* Get address itself*/
  713.       if (!strlen(address))
  714.       {
  715.          printmsg(0,"Could not locate expected address in header");
  716.          *count = 0;
  717.          return NULL;
  718.       } /* if */
  719.       else {
  720.          addrlist[*count] = newstr( address );
  721.                               /* Save permanent copy of address      */
  722.          checkref( addrlist[*count] ); /* Verify strdup worked       */
  723.          printmsg(4,"address[%d]= \"%s\"",*count, address);
  724.          *count += 1;         /* Flag we got the address             */
  725.       } /* else */
  726.  
  727.       if (fgets( buf, BUFSIZ, datain ) == NULL) /* End of file?      */
  728.          token = NULL;        /* Yes --> Odd, but no major problem   */
  729.       else if (*buf == '\n')  /* End of the header?                  */
  730.       {
  731.          token = NULL;        /* Yes --> Exit loop                   */
  732.          *header = FALSE;     /* Report to caller the header is done */
  733.          blind = FALSE;       /* Denote not a blind header           */
  734.       }
  735.       else if (isspace(*buf)) /* Another address?                    */
  736.          token = buf;         /* Yes --> Write it out                */
  737.       else {                  /* No --> Determine what next header is*/
  738.          blind = FALSE;       /* Assume not a blind header           */
  739.          if (equalni(&cc[offset], buf, cclen))   /* Cc: header?       */
  740.             token = strpbrk(buf," \t");
  741.          else if (equalni(&bcc[offset], buf, bcclen))  /* Bcc: header?*/
  742.          {
  743.             token = strpbrk(buf ," \t");
  744.             blind = TRUE;
  745.          } /* if */
  746.          else                 /* Unsupported header, exit loop       */
  747.             token = NULL;
  748.       } /* else */
  749.       if ( ! blind )
  750.          fputs(buf, dataout );
  751.    } while (token != NULL );
  752.  
  753. /*--------------------------------------------------------------------*/
  754. /*                   Return address list to caller                    */
  755. /*--------------------------------------------------------------------*/
  756.  
  757.    return addrlist;
  758.  
  759. } /* Parse822 */
  760.  
  761. /*--------------------------------------------------------------------*/
  762. /*    C o p y T e m p                                                 */
  763. /*                                                                    */
  764. /*    Copy the un-parsed parts of a message into the holding file     */
  765. /*--------------------------------------------------------------------*/
  766.  
  767. static boolean CopyTemp( void )
  768. {
  769.    boolean header = TRUE;
  770.    char buf[BUFSIZ];
  771.    boolean newline = TRUE;
  772.  
  773.    while (fgets(buf, BUFSIZ, datain) != NULL)
  774.    {
  775.       if (header)
  776.       {
  777.          if (*buf == '\n')
  778.             header = FALSE;
  779.          else if (equalni(received, buf, receivedlen))
  780.             hops++;
  781.       }
  782.  
  783.       newline = buf[ strlen( buf ) - 1 ] == '\n';
  784.  
  785.       if (fputs(buf, dataout) == EOF)  /* I/O error?                 */
  786.       {
  787.          printerr(tempname);
  788.          printmsg(0,"I/O error on \"%s\"", tempname);
  789.          fclose(dataout);
  790.          return FALSE;
  791.       } /* if */
  792.    } /* while */
  793.  
  794.    if (ferror(datain))        /* Clean end of file on input?         */
  795.    {
  796.       printerr(namein);
  797.       Terminate(7);
  798.    }
  799.  
  800.    if ( !newline )            /* Is the file terminated properly?    */
  801.    {
  802.       printmsg(0, "rmail: Improperly formed message, adding final newline!");
  803.       fputc( '\n', dataout );
  804.    }
  805.  
  806.    return header;
  807. }  /* CopyTemp */
  808.  
  809. /*--------------------------------------------------------------------*/
  810. /*    D a e m o n M a i l                                             */
  811. /*                                                                    */
  812. /*    Send text in a mailbag file to address(es) specified by address */
  813. /*--------------------------------------------------------------------*/
  814.  
  815. static boolean DaemonMail( const char *subject,
  816.                           char **address,
  817.                           int count )
  818. {
  819.    char buf[BUFSIZ];
  820.    char *logname;
  821.    char *token;
  822.    char *moi = NULL;
  823.    struct UserTable *userp;
  824.    char *header = "To:";
  825.    char *cc     = "Cc:";
  826.    boolean print = TRUE;
  827.  
  828. /*--------------------------------------------------------------------*/
  829. /*                         Validate the input                         */
  830. /*--------------------------------------------------------------------*/
  831.  
  832.    if ( count == 0 )
  833.    {
  834.       printmsg(0,"rmail: No addresseses to deliver to!");
  835.       return FALSE;
  836.    }
  837.  
  838. /*--------------------------------------------------------------------*/
  839. /*                       Determine our user id                        */
  840. /*--------------------------------------------------------------------*/
  841.  
  842.    logname = getenv( LOGNAME );
  843.    if ( logname == NULL )
  844.       logname = E_mailbox;
  845.  
  846. /*--------------------------------------------------------------------*/
  847. /*              Get the name of the user, or make one up              */
  848. /*--------------------------------------------------------------------*/
  849.  
  850.    userp = checkuser(logname);   /* Locate user id in host table     */
  851.  
  852.    if ( (userp != BADUSER) &&
  853.         (userp->realname != NULL) &&
  854.          !equal(userp->realname, EMPTY_GCOS ))
  855.       moi = userp->realname;
  856.    else if ( equali(logname, E_postmaster) || equali(logname, POSTMASTER))
  857.       moi = "Postmaster";
  858.    else if ( equali( logname, "uucp" ))
  859.       moi = "Unix to Unix Copy";
  860.    else
  861.       moi = logname;          /* Dummy to ease formatting From: line  */
  862.  
  863. /*--------------------------------------------------------------------*/
  864. /*    Add the boilerplate the front:                                  */
  865. /*                                                                    */
  866. /*       Date, From, Organization, and Reply-To                       */
  867. /*--------------------------------------------------------------------*/
  868.  
  869.    fprintf(dataout,"%-10s by %s (%s %s);\n%-10s %s\n",
  870.               "Received:",E_domain,compilep, compilev,
  871.               " ", now );
  872.  
  873. /*--------------------------------------------------------------------*/
  874. /*                       Generate a message-id                        */
  875. /*--------------------------------------------------------------------*/
  876.  
  877.    sprintf(buf, "<%lx.%s@%s>", time( NULL ) , E_nodename, E_domain);
  878.    PutHead("Message-ID:", buf, dataout , FALSE );
  879.    PutHead(NULL, NULL, dataout , FALSE );
  880.  
  881.    PutHead("Date:", arpadate() , dataout, FALSE);
  882.  
  883.    if (bflag[F_BANG])
  884.       sprintf(buf, "(%s) %s!%s", moi, E_nodename, logname );
  885.    else {
  886.       checkname( E_nodename );  /* Force loading of the E_fdomain name */
  887.       sprintf(buf, "\"%s\" <%s@%s>", moi, logname , E_fdomain );
  888.    }
  889.  
  890.    PutHead("From:", buf, dataout, FALSE );
  891.  
  892.    if (E_organization != NULL )
  893.       PutHead("Organization:", E_organization, dataout, FALSE);
  894.  
  895. /*--------------------------------------------------------------------*/
  896. /*                      Write the address out                         */
  897. /*--------------------------------------------------------------------*/
  898.  
  899.    while( (count-- > 0) && print )
  900.    {
  901.       token = *address++;
  902.       if ( *token == '-')  /* Option flag?                        */
  903.       {
  904.          if (token[1] == 'c')
  905.          {
  906.             header = cc;
  907.             cc = "";
  908.          }
  909.          else if (token[1] == 'b')
  910.             print = FALSE;
  911.          else
  912.             printmsg(0,"rmail: Invalid flag \"%s\" ignored!", token);
  913.       } /* if ( token == '-') */
  914.       else if ( print )
  915.       {
  916.          if (strpbrk(token,"!@") == nil(char))
  917.          {
  918.             if (bflag[F_BANG])
  919.                sprintf(buf, "%s!%s", E_nodename, token );
  920.             else
  921.                sprintf(buf, "%s@%s", token , E_fdomain );
  922.             token = buf;
  923.          }
  924.  
  925.          PutHead(header , token, dataout, FALSE);
  926.          header = "";         /* Continue same field by default      */
  927.       }
  928.    } /* while( (count-- > 0) && print ) */
  929.  
  930. /*--------------------------------------------------------------------*/
  931. /*                     Handle the subject, if any                     */
  932. /*--------------------------------------------------------------------*/
  933.  
  934.    if (subject != NULL)
  935.       PutHead("Subject:", subject, dataout, FALSE);
  936.  
  937.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header line   */
  938.    PutHead(NULL, "", dataout, FALSE);  /* Terminate the header file   */
  939.  
  940. /*--------------------------------------------------------------------*/
  941. /*                          Return to caller                          */
  942. /*--------------------------------------------------------------------*/
  943.  
  944.    uuser = ruser = strncpy(fromuser, logname, sizeof fromuser);
  945.                               /* Define user for UUCP From line      */
  946.    fromuser[ sizeof fromuser - 1 ] = '\0';
  947.    rnode = bflag[F_BANG] ? E_nodename : E_fdomain;
  948.                               /* Use full domain address, if possible */
  949.  
  950.    strcpy(fromnode, E_nodename);/* Declare as local system           */
  951.    return TRUE;
  952.  
  953. } /*DaemonMail*/
  954.  
  955. /*--------------------------------------------------------------------*/
  956. /*    P u t H e a d                                                   */
  957. /*                                                                    */
  958. /*    Write one line of an RFC-822 header                             */
  959. /*--------------------------------------------------------------------*/
  960.  
  961.  static void PutHead( const char *label,
  962.                       const char *operand,
  963.                       FILE *stream,
  964.                       const boolean resent)
  965.  {
  966.    static boolean terminate = TRUE;
  967.  
  968.    if (label == NULL )        /* Terminate call?                     */
  969.    {                          /* Yes --> Reset Flag and return       */
  970.       fputc('\n', stream);    /* Terminate the current line          */
  971.       terminate = TRUE;
  972.       return;
  973.    } /* if */
  974.  
  975.    if (strlen(label))         /* First line of a header?             */
  976.    {
  977.       if (!terminate)         /* Terminate previous line?            */
  978.          fputc('\n', stream);
  979.  
  980.       if (resent)
  981.          fprintf(stream,"Resent-%s %s",label, operand);
  982.       else
  983.          fprintf(stream,"%-10s %s",label, operand);
  984.       terminate = FALSE;          /* Flag that we did not end file   */
  985.    } /* if */
  986.    else                       /* Continuing line                     */
  987.       fprintf(stream,",\n%-10s %s",label, operand);
  988.  } /* PutHead */
  989.  
  990. /*--------------------------------------------------------------------*/
  991. /*    u s a g e                                                       */
  992. /*                                                                    */
  993. /*    Report how the program works                                    */
  994. /*--------------------------------------------------------------------*/
  995.  
  996.  static void usage( void )
  997.  {
  998.  
  999.    static char syntax[] =
  1000.       "Usage:\tRMAIL\t-t [-x debug] [-f | -F file]\n"
  1001.       "\t\t-w [-x debug] [-f | -F file] [-s subject] addr1 [-c] addr2  [-b] addr3 ...\n"
  1002.       "\t\t[-x debug] [-f | -F file] addr1 addr2 addr3 ...\n";
  1003.  
  1004.    puts( syntax );
  1005.    exit(3);
  1006.  }
  1007.